package collection

import (
	"math"
	"sync"

	"gitee.com/gousing/values"
)

// StoreOnce 带初始化保护的单个数据寄存器（单例快捷实现）
type StoreOnce[T any] struct {
	val      T // 数据
	initFunc func() (val T)
	inited   bool
	once     sync.Once
}

// NewStoreOnce 带初始化保护的单个数据寄存器
//   - initFunc 初始化函数(首次读取时调用)
func NewStoreOnce[T any](initFunc func() (val T)) *StoreOnce[T] {
	return &StoreOnce[T]{initFunc: initFunc}
}

// Load 获取寄存器数据(未初始化时调用initFunc自动初始化)
func (v *StoreOnce[T]) Load() T {
	if v.inited {
		return v.val
	}
	v.once.Do(func() {
		v.val = v.initFunc()
		v.inited = true
	})
	return v.val
}

// Update 强制更新寄存的数据
func (v *StoreOnce[T]) Update(val T) {
	v.val = val
}

// StoreAny 带读写保护的单个数据寄存器
type StoreAny[T any] struct {
	val T // 数据
	mu  sync.RWMutex
}

// NewStoreAny 带读写保护的单个数据寄存器
func NewStoreAny[T any]() *StoreAny[T] {
	return &StoreAny[T]{mu: sync.RWMutex{}}
}

// NewStoreAnyWith 带读写保护的单个数据寄存器
func NewStoreAnyWith[T any](val T) *StoreAny[T] {
	return &StoreAny[T]{val: val}
}

// Set 设置/修改寄存的数据
func (v *StoreAny[T]) Set(val T) {
	v.mu.Lock()
	defer v.mu.Unlock()
	v.val = val
}

// Get 获取寄存的数据
func (v *StoreAny[T]) Get() T {
	v.mu.RLock()
	defer v.mu.RUnlock()
	return v.val
}

// StoreNumber 带读写保护的单个数值寄存器
type StoreNumber[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64] struct {
	val T // 数据
	mu  sync.RWMutex
}

// NewStoreNumber 带读写保护的单个数值寄存器
func NewStoreNumber[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64]() *StoreNumber[T] {
	return &StoreNumber[T]{mu: sync.RWMutex{}}
}

// NewStoreNumberWith 带读写保护的单个数值寄存器
func NewStoreNumberWith[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | float32 | float64](val T) *StoreNumber[T] {
	return &StoreNumber[T]{val: val}
}

// Set 设置/修改寄存的数值
func (v *StoreNumber[T]) Set(val T) {
	v.mu.Lock()
	defer v.mu.Unlock()
	v.val = val
}

// Get 获取寄存的数值
func (v *StoreNumber[T]) Get() T {
	v.mu.RLock()
	defer v.mu.RUnlock()
	return v.val
}

// Add 加上指定的数值, 更新寄存值并返回结果
func (v *StoreNumber[T]) Add(n T) T {
	v.mu.Lock()
	defer v.mu.Unlock()
	v.val += n
	return v.val
}

// Sub 减去指定的数值, 更新寄存值并返回结果
func (v *StoreNumber[T]) Sub(n T) T {
	v.mu.Lock()
	defer v.mu.Unlock()
	v.val -= n
	return v.val
}

// Divide 除以指定的数值, 更新寄存值并返回结果
func (v *StoreNumber[T]) Divide(n T) T {
	v.mu.Lock()
	defer v.mu.Unlock()
	if n == 0 {
		panic("StoreNumber.Divide, divisor is 0")
	}
	v.val = v.val / n
	return v.val
}

// Multiply 乘以指定的数值, 更新寄存值并返回结果
func (v *StoreNumber[T]) Multiply(n T) T {
	v.mu.Lock()
	defer v.mu.Unlock()
	v.val *= n
	return v.val
}

// PowX 自定义N次方, 更新寄存值并返回结果
//   - n 自定义N次方, 大于1时为正方, 小于1时为倒方
func (v *StoreNumber[T]) PowX(n int) T {
	v.mu.Lock()
	defer v.mu.Unlock()
	// 对于0这个特殊的数，0^0是没有确定值的，因为0没有唯一的倒数。
	if v.val == 0 {
		return 0
	}
	// 任何非零数的零次方都等于1
	if v.val == 1 || n == 0 {
		v.val = 1
		return 1
	}
	// n为1时，直接返回寄存值
	if n == 1 {
		return v.val
	}
	p := math.Pow(float64(v.val), float64(n))
	switch any(v.val).(type) {
	case int:
		v.val = T(int(p))
	case int8:
		v.val = T(int8(p))
	case int16:
		v.val = T(int16(p))
	case int32:
		v.val = T(int32(p))
	case int64:
		v.val = T(int64(p))
	case uint:
		v.val = T(uint(p))
	case uint8:
		v.val = T(uint8(p))
	case uint16:
		v.val = T(uint16(p))
	case uint32:
		v.val = T(uint32(p))
	case uint64:
		v.val = T(uint64(p))
	case float32:
		v.val = T(float32(p))
	case float64:
		v.val = T(p)
	default:
		panic("StoreNumber.ToSquareX, type error")
	}
	return v.val
}

// Mod 取余数, 更新寄存值并返回结果
//   - floatPrec: 浮点数小数精度, 仅对浮点数有效，默认小数精度为2位
func (v *StoreNumber[T]) Mod(n T, floatPrec ...int) (val T) {
	if n == 0 {
		panic("StoreNumber.Mod, divisor is 0")
	}
	v.mu.Lock()
	defer v.mu.Unlock()
	var x any = v.val
	switch t := x.(type) {
	case int:
		val = T(t % int(n))
	case int8:
		val = T(t % int8(n))
	case int16:
		val = T(t % int16(n))
	case int32:
		val = T(t % int32(n))
	case int64:
		val = T(t % int64(n))
	case uint:
		val = T(t % uint(n))
	case uint8:
		val = T(t % uint8(n))
	case uint16:
		val = T(t % uint16(n))
	case uint32:
		val = T(t % uint32(n))
	case uint64:
		val = T(t % uint64(n))
	case float32:
		if len(floatPrec) > 0 {
			val = T(values.RoundFloat32(float32(math.Mod(float64(t), float64(n))), floatPrec[0]))
		} else {
			val = T(values.RoundFloat32(float32(math.Mod(float64(t), float64(n))), 2))
		}
	case float64:
		if len(floatPrec) > 0 {
			val = T(values.RoundFloat64((math.Mod(t, float64(n))), floatPrec[0]))
		} else {
			val = T(values.RoundFloat64((math.Mod(t, float64(n))), 2))
		}
	default:
		panic("StoreNumber.Mod, type error")
	}
	v.val = val
	return
}

// ToAdd 加上指定的数值，计算后返回结果(不更新寄存值)
func (v *StoreNumber[T]) ToAdd(n T) (val T) {
	v.mu.RLock()
	defer v.mu.RUnlock()
	return v.val + n
}

// ToSub 减去指定的数值，计算后返回结果(不更新寄存值)
func (v *StoreNumber[T]) ToSub(n T) (val T) {
	v.mu.RLock()
	defer v.mu.RUnlock()
	return v.val - n
}

// ToDivide 除以指定的数值，计算后返回结果(不更新寄存值)
func (v *StoreNumber[T]) ToDivide(n T) (val T) {
	v.mu.RLock()
	defer v.mu.RUnlock()
	if n == 0 {
		panic("StoreNumber.ToDivide, divisor is 0")
	}
	return v.val / n
}

// ToMultiply 乘以指定的数值，计算后返回结果(不更新寄存值)
func (v *StoreNumber[T]) ToMultiply(n T) (val T) {
	v.mu.RLock()
	defer v.mu.RUnlock()
	return v.val * n
}

// ToPowX 自定义N次方，计算后返回结果(不更新寄存值)
func (v *StoreNumber[T]) ToPowX(n int) (val T) {
	v.mu.RLock()
	defer v.mu.RUnlock()
	// 对于0这个特殊的数，0^0是没有确定值的，因为0没有唯一的倒数。
	if v.val == 0 {
		return 0
	}
	// 任何非零数的零次方都等于1
	if v.val == 1 || n == 0 {
		return 1
	}
	// n为1时，直接返回寄存值
	if n == 1 {
		return v.val
	}
	p := math.Pow(float64(val), float64(n))
	switch any(v.val).(type) {
	case int:
		return T(int(p))
	case int8:
		return T(int8(p))
	case int16:
		return T(int16(p))
	case int32:
		return T(int32(p))
	case int64:
		return T(int64(p))
	case uint:
		return T(uint(p))
	case uint8:
		return T(uint8(p))
	case uint16:
		return T(uint16(p))
	case uint32:
		return T(uint32(p))
	case uint64:
		return T(uint64(p))
	case float32:
		return T(float32(p))
	case float64:
		return T(p)
	default:
		panic("StoreNumber.ToSquareX, type error")
	}
}

// ToMod 取余数，计算后返回结果(不更新寄存值)
//   - floatPrec: 浮点数小数精度, 仅对浮点数有效，默认小数精度为2位
func (v *StoreNumber[T]) ToMod(n T, floatPrec ...int) (val T) {
	if n == 0 {
		panic("StoreNumber.ToMod, divisor is 0")
	}
	v.mu.RLock()
	defer v.mu.RUnlock()
	var x any = v.val
	switch t := x.(type) {
	case int:
		return T(t % int(n))
	case int8:
		return T(t % int8(n))
	case int16:
		return T(t % int16(n))
	case int32:
		return T(t % int32(n))
	case int64:
		return T(t % int64(n))
	case uint:
		return T(t % uint(n))
	case uint8:
		return T(t % uint8(n))
	case uint16:
		return T(t % uint16(n))
	case uint32:
		return T(t % uint32(n))
	case uint64:
		return T(t % uint64(n))
	case float32:
		if len(floatPrec) > 0 {
			return T(values.RoundFloat32(float32(math.Mod(float64(t), float64(n))), floatPrec[0]))
		}
		return T(values.RoundFloat32(float32(math.Mod(float64(t), float64(n))), 2))
	case float64:
		if len(floatPrec) > 0 {
			return T(values.RoundFloat64((math.Mod(t, float64(n))), floatPrec[0]))
		}
		return T(values.RoundFloat64((math.Mod(t, float64(n))), 2))
	default:
		panic("StoreNumber.ToMod, type error")
	}
}
